package main

import (
	"context"
	"database/sql"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/ev-charging/cloud-platform/config"
	"github.com/ev-charging/cloud-platform/internal/api/handlers"
	"github.com/ev-charging/cloud-platform/internal/cache"
	"github.com/ev-charging/cloud-platform/internal/device"
	"github.com/ev-charging/cloud-platform/internal/messaging"
	"github.com/ev-charging/cloud-platform/internal/pricing"
	"github.com/ev-charging/cloud-platform/web"
)

func main() {
	// 解析命令行参数
	configPath := flag.String("config", "configs/config.yaml", "配置文件路径")
	flag.Parse()

	// 加载配置
	cfg, err := config.Load(*configPath)
	if err != nil {
		log.Fatalf("加载配置文件失败: %v", err)
	}

	// 初始化数据库连接
	db, err := initDatabase(cfg.Database)
	if err != nil {
		log.Fatalf("初始化数据库失败: %v", err)
	}
	defer closeDatabase(db)

	// 初始化Redis缓存
	redisClient, err := cache.InitRedis(cfg.Redis)
	if err != nil {
		log.Fatalf("初始化Redis失败: %v", err)
	}
	defer cache.Close()

	// 初始化Kafka生产者
	kafkaProducer, err := messaging.InitKafkaProducer(cfg.Kafka.Brokers)
	if err != nil {
		log.Fatalf("初始化Kafka生产者失败: %v", err)
	}
	defer messaging.CloseKafkaProducer(kafkaProducer)

	// 初始化Kafka消费者
	kafkaConsumer, err := messaging.InitKafkaConsumer(cfg.Kafka.Brokers, cfg.Kafka.GroupID)
	if err != nil {
		log.Fatalf("初始化Kafka消费者失败: %v", err)
	}
	defer messaging.CloseKafkaConsumer(kafkaConsumer)

	// 启动设备连接服务(MQTT)
	deviceService := device.NewService(cfg.MQTT, kafkaProducer)
	go func() {
		if err := deviceService.Start(); err != nil {
			log.Printf("设备服务启动失败: %v", err)
		}
	}()

	// 启动Kafka消息处理器
	messageHandler := messaging.NewKafkaMessageHandler(kafkaConsumer, db, redisClient)
	go func() {
		if err := messageHandler.Start(); err != nil {
			log.Printf("消息处理器启动失败: %v", err)
		}
	}()

	// 初始化电价策略引擎
	pricingEngine := pricing.NewPricingEngine(&cfg.Pricing)
	go func() {
		// 定期更新电价策略
		updateInterval, err := time.ParseDuration(cfg.Pricing.UpdateInterval)
		if err != nil {
			log.Printf("解析电价更新间隔失败: %v", err)
			updateInterval = 1 * time.Hour
		}

		ticker := time.NewTicker(updateInterval)
		defer ticker.Stop()

		for range ticker.C {
			pricingEngine.UpdateRates(&cfg.Pricing)
			log.Println("电价策略已更新")
		}
	}()

	// 创建处理器
	deviceHandler := handlers.NewDeviceHandler(deviceService)
	pricingHandler := handlers.NewPricingHandler(pricingEngine)

	// 创建Web服务器
	webServer := web.NewServer(&cfg.Server, deviceHandler, pricingHandler)

	// 启动HTTP服务
	go func() {
		log.Printf("HTTP服务启动，监听端口: %s", cfg.Server.Port)
		if err := webServer.Run(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("HTTP服务启动失败: %v", err)
		}
	}()

	// 优雅关闭
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Println("正在关闭服务...")

	_, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 停止所有服务
	deviceService.Stop()
	messageHandler.Stop()

	log.Println("服务已关闭")
}

func initDatabase(cfg config.DatabaseConfig) (*sql.DB, error) {
	var dsn string
	switch cfg.Driver {
	case "postgres":
		dsn = fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.DBName, cfg.SSLMode)
	case "mysql":
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true&loc=Local", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DBName)
	default:
		return nil, fmt.Errorf("不支持的数据库驱动: %s", cfg.Driver)
	}

	db, err := sql.Open(cfg.Driver, dsn)
	if err != nil {
		return nil, fmt.Errorf("sql.Open 失败: %w", err)
	}

	// 设置连接池参数
	db.SetMaxOpenConns(cfg.MaxOpenConns)
	db.SetMaxIdleConns(cfg.MaxIdleConns)

	// 解析连接最大存活时间
	maxLifetime, err := time.ParseDuration(cfg.ConnMaxLifetime)
	if err != nil {
		return nil, fmt.Errorf("解析数据库连接最大生命周期失败: %w", err)
	}
	db.SetConnMaxLifetime(maxLifetime)

	// 验证连接
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := db.PingContext(ctx); err != nil {
		return nil, fmt.Errorf("数据库连接失败: %w", err)
	}

	return db, nil
}

// closeDatabase 关闭数据库连接
func closeDatabase(db *sql.DB) {
	if db != nil {
		if err := db.Close(); err != nil {
			log.Printf("关闭数据库连接失败: %v", err)
		}
	}
}
